package gui.components;

import gui.listeners.ViewportMouseListener;

import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

public class Viewport extends JPanel{
  private static final long serialVersionUID = 1L;
	private BufferedImage image;
	private Rectangle imageTransform;
	private float scaleFactor = 1;
	private boolean resizeToFitScreen = true;
	private Point storedPosition;
	private ViewportMouseListener vml;
	
	public Viewport(){
		super();
		imageTransform = new Rectangle();
		vml = new ViewportMouseListener(this);
		
	  
	  addMouseListener(vml);
	  addMouseMotionListener(vml);
	  addMouseWheelListener(vml);
	}
	
	public void setImage(BufferedImage img){
		vml.setEnabled(true);
		resizeToFitScreen = (image == null);
		this.image = img;
		recalculateSize();
		repaint();
	}
	
	public void setResizeToFitScreen(boolean resize){
		resizeToFitScreen = resize;
		if(resize) repaint();
	}
	
	public void storePosition(){
		storedPosition = imageTransform.getLocation();
	}
	
	public void translateByOffset(int xOffset, int yOffset, boolean useStoredPosition){
		if(useStoredPosition){
			imageTransform.setLocation(storedPosition);
		}
		
		resizeToFitScreen = false;
		
		imageTransform.x += xOffset;
		imageTransform.y += yOffset;
		
		repaint();
	}
	
	private void recalculateSize(){
		imageTransform.width = (int)((float)image.getWidth() * scaleFactor);
		imageTransform.height = (int)((float)image.getHeight() * scaleFactor);
	}
	
	private void resizeToFitScreen(){
		float imgWidth = image.getWidth();
		float imgHeight = image.getHeight();
		float vpWidth = (float)getBounds().getWidth();
		float vpHeight = (float)getBounds().getHeight();
		
		float imgSideRatio = imgHeight / imgWidth;
		float vpSideRatio = vpHeight / vpWidth;
		
		scaleFactor = (imgSideRatio < vpSideRatio) ? (vpWidth / imgWidth) : (vpHeight / imgHeight);
		int width = (int)(imgWidth * scaleFactor);
		int height = (int)(imgHeight * scaleFactor);
		
		int x = (int)((vpWidth / 2) - (imgWidth * scaleFactor / 2));
		int y = (int)((vpHeight / 2) - (imgHeight * scaleFactor / 2));
		
		imageTransform.setBounds(x, y, width, height);
	}
	
	public void resizeImageByFactor(float factor, Point position){
		resizeToFitScreen = false;
		if(position == null || !imageTransform.contains(position)){
			position = new Point(
					imageTransform.x + imageTransform.width / 2, 
					imageTransform.y + imageTransform.height / 2);
		}
		int x = (int)((float)(imageTransform.x - position.x) * factor + position.x);
		int y = (int)((float)(imageTransform.y - position.y) * factor + position.y);
		scaleFactor *= factor;
		int width = (int)(image.getWidth() * scaleFactor);
		int height = (int)(image.getHeight() * scaleFactor);
		
		
		imageTransform.setBounds(x, y, width, height);
		
		repaint();
	}
	
	public void resizeImageToScale(float scale, Point position){
		float factor = scaleFactor / scale;
		resizeImageByFactor(factor, position);
	}
	
	public float getScale(){
		return scaleFactor;
	}

	@Override
  public void paint(Graphics g) {
	  
	  if(image != null){
	  	if(resizeToFitScreen){
		  	resizeToFitScreen();
	  	}
	  	g.setColor(getBackground());
	  	g.fillRect(0, 0, getWidth(), getHeight());
	  	
	  	g.drawImage(
	  			image, 
	  			imageTransform.x, 
	  			imageTransform.y, 
	  			imageTransform.width,
	  			imageTransform.height, null);
	  }
	  else{
	  	g.setColor(getBackground());
	  	g.fillRect(0, 0, getWidth(), getHeight());
	  }
  }	
	
}
